home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / X11R4 / cmds / X / dix / RCS / resource.c,v < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-14  |  13.6 KB  |  552 lines

  1. head     1.1;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.1
  10. date     90.02.14.15.23.33;  author tve;  state Exp;
  11. branches ;
  12. next     ;
  13.  
  14.  
  15. desc
  16. @Original X11R4 distribution
  17. @
  18.  
  19.  
  20.  
  21. 1.1
  22. log
  23. @Initial revision
  24. @
  25. text
  26. @/************************************************************
  27. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
  28. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  29.  
  30.                         All Rights Reserved
  31.  
  32. Permission to use, copy, modify, and distribute this software and its 
  33. documentation for any purpose and without fee is hereby granted, 
  34. provided that the above copyright notice appear in all copies and that
  35. both that copyright notice and this permission notice appear in 
  36. supporting documentation, and that the names of Digital or MIT not be
  37. used in advertising or publicity pertaining to distribution of the
  38. software without specific, written prior permission.  
  39.  
  40. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  41. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  42. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  43. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  44. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  45. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  46. SOFTWARE.
  47.  
  48. ********************************************************/
  49.  
  50. /* $XConsortium: resource.c,v 1.79 89/10/08 15:16:32 rws Exp $ */
  51.  
  52. /*    Routines to manage various kinds of resources:
  53.  *
  54.  *    CreateNewResourceType, CreateNewResourceClass, InitClientResources,
  55.  *    FakeClientID, AddResource, FreeResource, FreeClientResources,
  56.  *    FreeAllResources, LookupIDByType, LookupIDByClass
  57.  */
  58.  
  59. /* 
  60.  *      a resource is a 32 bit quantity.  the upper 12 bits are client id.  
  61.  *      client provides a 19 bit resource id. this is "hashed" by me by
  62.  *      taking the 10 lower bits and xor'ing with the mid 10 bits.
  63.  *
  64.  *      It is sometimes necessary for the server to create an ID that looks
  65.  *      like it belongs to a client.  This ID, however,  must not be one
  66.  *      the client actually can create, or we have the potential for conflict.
  67.  *      The 20th bit of the ID is resevered for the server's use for this
  68.  *      purpose.  By setting CLIENT_ID(id) to the client, the SERVER_BIT to
  69.  *      1, and an otherwise unused ID in the low 19 bits, we can create a
  70.  *      resource "owned" by the client.
  71.  *      
  72.  *      The following IDs are currently reserved for siccing on the client:
  73.  *      1 - allocated color to be freed when the client dies
  74.  */
  75.  
  76. #include "X.h"
  77. #include "misc.h"
  78. #include "os.h"
  79. #include "resource.h"
  80. #include "dixstruct.h" 
  81. #include "opaque.h"
  82.  
  83. extern void HandleSaveSet();
  84. extern void FlushClientCaches();
  85. static void RebuildTable();
  86.  
  87. #define INITBUCKETS 64
  88. #define INITHASHSIZE 6
  89. #define MAXHASHSIZE 11
  90.  
  91. typedef struct _Resource {
  92.     struct _Resource    *next;
  93.     XID            id;
  94.     RESTYPE        type;
  95.     pointer        value;
  96. } ResourceRec, *ResourcePtr;
  97. #define NullResource ((ResourcePtr)NULL)
  98.  
  99. typedef struct _ClientResource {
  100.     ResourcePtr *resources;
  101.     int        elements;
  102.     int        buckets;
  103.     int        hashsize;    /* log(2)(buckets) */
  104.     XID        fakeID;
  105.     XID        expectID;
  106. } ClientResourceRec;
  107.  
  108. static RESTYPE lastResourceType;
  109. static RESTYPE lastResourceClass;
  110. static RESTYPE TypeMask;
  111.  
  112. typedef int (*DeleteType)();
  113.  
  114. static DeleteType *DeleteFuncs = (DeleteType *)NULL;
  115.  
  116. RESTYPE
  117. CreateNewResourceType(deleteFunc)
  118.     DeleteType deleteFunc;
  119. {
  120.     RESTYPE next = lastResourceType + 1;
  121.     DeleteType *funcs;
  122.  
  123.     if (next & lastResourceClass)
  124.     return 0;
  125.     funcs = (DeleteType *)xrealloc(DeleteFuncs,
  126.                    (next + 1) * sizeof(DeleteType));
  127.     if (!funcs)
  128.     return 0;
  129.     lastResourceType = next;
  130.     DeleteFuncs = funcs;
  131.     DeleteFuncs[next] = deleteFunc;
  132.     return next;
  133. }
  134.  
  135. RESTYPE
  136. CreateNewResourceClass()
  137. {
  138.     RESTYPE next = lastResourceClass >> 1;
  139.  
  140.     if (next & lastResourceType)
  141.     return 0;
  142.     lastResourceClass = next;
  143.     TypeMask = next - 1;
  144.     return next;
  145. }
  146.  
  147. ClientResourceRec clientTable[MAXCLIENTS];
  148.  
  149. /*****************
  150.  * InitClientResources
  151.  *    When a new client is created, call this to allocate space
  152.  *    in resource table
  153.  *****************/
  154.  
  155. Bool
  156. InitClientResources(client)
  157.     ClientPtr client;
  158. {
  159.     register int i, j;
  160.  
  161.     if (client == serverClient)
  162.     {
  163.     extern int DeleteWindow(), dixDestroyPixmap(), FreeGC();
  164.     extern int CloseFont(), FreeCursor();
  165.     extern int FreeColormap(), FreeClientPixels();
  166.     extern int OtherClientGone(), DeletePassiveGrab();
  167.  
  168.     lastResourceType = RT_LASTPREDEF;
  169.     lastResourceClass = RC_LASTPREDEF;
  170.     TypeMask = RC_LASTPREDEF - 1;
  171.     if (DeleteFuncs)
  172.         xfree(DeleteFuncs);
  173.     DeleteFuncs = (DeleteType *)xalloc((lastResourceType + 1) *
  174.                        sizeof(DeleteType));
  175.     if (!DeleteFuncs)
  176.         return FALSE;
  177.     DeleteFuncs[RT_WINDOW & TypeMask] = DeleteWindow;
  178.     DeleteFuncs[RT_PIXMAP & TypeMask] = dixDestroyPixmap;
  179.     DeleteFuncs[RT_GC & TypeMask] = FreeGC;
  180.     DeleteFuncs[RT_FONT & TypeMask] = CloseFont;
  181.     DeleteFuncs[RT_CURSOR & TypeMask] = FreeCursor;
  182.     DeleteFuncs[RT_COLORMAP & TypeMask] = FreeColormap;
  183.     DeleteFuncs[RT_CMAPENTRY & TypeMask] = FreeClientPixels;
  184.     DeleteFuncs[RT_OTHERCLIENT & TypeMask] = OtherClientGone;
  185.     DeleteFuncs[RT_PASSIVEGRAB & TypeMask] = DeletePassiveGrab;
  186.     }
  187.     clientTable[i = client->index].resources =
  188.     (ResourcePtr *)xalloc(INITBUCKETS*sizeof(ResourcePtr));
  189.     if (!clientTable[i].resources)
  190.     return FALSE;
  191.     clientTable[i].buckets = INITBUCKETS;
  192.     clientTable[i].elements = 0;
  193.     clientTable[i].hashsize = INITHASHSIZE;
  194.     clientTable[i].fakeID = 100;
  195.     clientTable[i].expectID = client->clientAsMask;
  196.     for (j=0; j<INITBUCKETS; j++) 
  197.     {
  198.         clientTable[i].resources[j] = NullResource;
  199.     }
  200.     return TRUE;
  201. }
  202.  
  203. static int
  204. Hash(client, id)
  205.     int client;
  206.     register XID id;
  207. {
  208.     id &= RESOURCE_ID_MASK;
  209.     switch (clientTable[client].hashsize)
  210.     {
  211.     case 6:
  212.         return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12))));
  213.     case 7:
  214.         return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13))));
  215.     case 8:
  216.         return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16))));
  217.     case 9:
  218.         return ((int)(0x1FF & (id ^ (id>>9))));
  219.     case 10:
  220.         return ((int)(0x3FF & (id ^ (id>>10))));
  221.     case 11:
  222.         return ((int)(0x7FF & (id ^ (id>>11))));
  223.     }
  224.     return -1;
  225. }
  226.  
  227. XID
  228. FakeClientID(client)
  229.     int client;
  230. {
  231.     return (
  232.         (client<<CLIENTOFFSET) + (SERVER_BIT) +
  233.         ((clientTable[client].fakeID++) & RESOURCE_ID_MASK));
  234. }
  235.  
  236. Bool
  237. AddResource(id, type, value)
  238.     XID id;
  239.     RESTYPE type;
  240.     pointer value;
  241. {
  242.     int client;
  243.     register ClientResourceRec *rrec;
  244.     register ResourcePtr res, *head;
  245.         
  246.     client = CLIENT_ID(id);
  247.     rrec = &clientTable[client];
  248.     if (!rrec->buckets)
  249.     {
  250.     ErrorF("AddResource(%x, %x, %x), client=%d \n",
  251.         id, type, value, client);
  252.         FatalError("client not in use\n");
  253.     }
  254.     if ((rrec->elements >= 4*rrec->buckets) &&
  255.     (rrec->hashsize < MAXHASHSIZE))
  256.     RebuildTable(client);
  257.     head = &rrec->resources[Hash(client, id)];
  258.     res = (ResourcePtr)xalloc(sizeof(ResourceRec));
  259.     if (!res)
  260.     {
  261.     (*DeleteFuncs[type & TypeMask])(value, id);
  262.     return FALSE;
  263.     }
  264.     res->next = *head;
  265.     res->id = id;
  266.     res->type = type;
  267.     res->value = value;
  268.     *head = res;
  269.     rrec->elements++;
  270.     if (!(id & SERVER_BIT) && (id >= rrec->expectID))
  271.     rrec->expectID = id + 1;
  272.     return TRUE;
  273. }
  274.  
  275. static void
  276. RebuildTable(client)
  277.     int client;
  278. {
  279.     register int j;
  280.     register ResourcePtr res, next;
  281.     ResourcePtr **tails, *resources;
  282.     register ResourcePtr **tptr, *rptr;
  283.  
  284.     /*
  285.      * For now, preserve insertion order, since some ddx layers depend
  286.      * on resources being free in the opposite order they are added.
  287.      */
  288.  
  289.     j = 2 * clientTable[client].buckets;
  290.     tails = (ResourcePtr **)ALLOCATE_LOCAL(j * sizeof(ResourcePtr *));
  291.     if (!tails)
  292.     return;
  293.     resources = (ResourcePtr *)xalloc(j * sizeof(ResourcePtr));
  294.     if (!resources)
  295.     {
  296.     DEALLOCATE_LOCAL(tails);
  297.     return;
  298.     }
  299.     for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++)
  300.     {
  301.     *rptr = NullResource;
  302.     *tptr = rptr;
  303.     }
  304.     clientTable[client].hashsize++;
  305.     for (j = clientTable[client].buckets,
  306.      rptr = clientTable[client].resources;
  307.      --j >= 0;
  308.      rptr++)
  309.     {
  310.     for (res = *rptr; res; res = next)
  311.     {
  312.         next = res->next;
  313.         res->next = NullResource;
  314.         tptr = &tails[Hash(client, res->id)];
  315.         **tptr = res;
  316.         *tptr = &res->next;
  317.     }
  318.     }
  319.     DEALLOCATE_LOCAL(tails);
  320.     clientTable[client].buckets *= 2;
  321.     xfree(clientTable[client].resources);
  322.     clientTable[client].resources = resources;
  323. }
  324.  
  325. void
  326. FreeResource(id, skipDeleteFuncType)
  327.     XID id;
  328.     RESTYPE skipDeleteFuncType;
  329. {
  330.     int        cid;
  331.     register    ResourcePtr res;
  332.     register    ResourcePtr *prev, *head;
  333.     register    int *eltptr;
  334.     int        elements;
  335.     Bool    gotOne = FALSE;
  336.  
  337.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  338.     {
  339.     head = &clientTable[cid].resources[Hash(cid, id)];
  340.     eltptr = &clientTable[cid].elements;
  341.  
  342.     prev = head;
  343.     while (res = *prev)
  344.     {
  345.         if (res->id == id)
  346.         {
  347.         RESTYPE rtype = res->type;
  348.         *prev = res->next;
  349.         elements = --*eltptr;
  350.         if (rtype & RC_CACHED)
  351.             FlushClientCaches(res->id);
  352.         if (rtype != skipDeleteFuncType)
  353.             (*DeleteFuncs[rtype & TypeMask])(res->value, res->id);
  354.         xfree(res);
  355.         if (*eltptr != elements)
  356.             prev = head; /* prev may no longer be valid */
  357.         gotOne = TRUE;
  358.         }
  359.         else
  360.         prev = &res->next;
  361.         }
  362.     if(clients[cid] && (id == clients[cid]->lastDrawableID))
  363.     {
  364.         clients[cid]->lastDrawable = (DrawablePtr) NULL;
  365.         clients[cid]->lastDrawableID = INVALID;
  366.     }
  367.     }
  368.     if (!gotOne)
  369.     FatalError("Freeing resource id=%X which isn't there", id);
  370. }
  371. void
  372. FreeResourceByType(id, type, skipFree)
  373.     XID id;
  374.     RESTYPE type;
  375.     Bool    skipFree;
  376. {
  377.     int        cid;
  378.     register    ResourcePtr res;
  379.     register    ResourcePtr *prev, *head;
  380.  
  381.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  382.     {
  383.     head = &clientTable[cid].resources[Hash(cid, id)];
  384.  
  385.     prev = head;
  386.     while (res = *prev)
  387.     {
  388.         if (res->id == id && res->type == type)
  389.         {
  390.         *prev = res->next;
  391.         if (type & RC_CACHED)
  392.             FlushClientCaches(res->id);
  393.         if (!skipFree)
  394.             (*DeleteFuncs[type & TypeMask])(res->value, res->id);
  395.         xfree(res);
  396.         break;
  397.         }
  398.         else
  399.         prev = &res->next;
  400.         }
  401.     if(clients[cid] && (id == clients[cid]->lastDrawableID))
  402.     {
  403.         clients[cid]->lastDrawable = (DrawablePtr) NULL;
  404.         clients[cid]->lastDrawableID = INVALID;
  405.     }
  406.     }
  407. }
  408.  
  409. /*
  410.  * Change the value associated with a resource id.  Caller
  411.  * is responsible for "doing the right thing" with the old
  412.  * data
  413.  */
  414.  
  415. Bool
  416. ChangeResourceValue (id, rtype, value)
  417.     XID    id;
  418.     RESTYPE rtype;
  419.     pointer value;
  420. {
  421.     int    cid;
  422.     register    ResourcePtr res;
  423.  
  424.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  425.     {
  426.     res = clientTable[cid].resources[Hash(cid, id)];
  427.  
  428.     for (; res; res = res->next)
  429.         if ((res->id == id) && (res->type == rtype))
  430.         {
  431.         if (rtype & RC_CACHED)
  432.             FlushClientCaches(res->id);
  433.         res->value = value;
  434.         return TRUE;
  435.         }
  436.     }
  437.     return FALSE;
  438. }
  439.  
  440. void
  441. FreeClientResources(client)
  442.     ClientPtr client;
  443. {
  444.     register ResourcePtr *resources;
  445.     register ResourcePtr this;
  446.     int j;
  447.  
  448.     /* This routine shouldn't be called with a null client, but just in
  449.     case ... */
  450.  
  451.     if (!client)
  452.     return;
  453.  
  454.     HandleSaveSet(client);
  455.  
  456.     resources = clientTable[client->index].resources;
  457.     for (j=0; j < clientTable[client->index].buckets; j++) 
  458.     {
  459.         /* It may seem silly to update the head of this resource list as
  460.     we delete the members, since the entire list will be deleted any way, 
  461.     but there are some resource deletion functions "FreeClientPixels" for 
  462.     one which do a LookupID on another resource id (a Colormap id in this
  463.     case), so the resource list must be kept valid up to the point that
  464.     it is deleted, so every time we delete a resource, we must update the
  465.     head, just like in FreeResource. I hope that this doesn't slow down
  466.     mass deletion appreciably. PRH */
  467.  
  468.     ResourcePtr *head;
  469.  
  470.     head = &resources[j];
  471.  
  472.         for (this = *head; this; this = *head)
  473.     {
  474.         RESTYPE rtype = this->type;
  475.         *head = this->next;
  476.         if (rtype & RC_CACHED)
  477.         FlushClientCaches(this->id);
  478.         (*DeleteFuncs[rtype & TypeMask])(this->value, this->id);
  479.         xfree(this);        
  480.     }
  481.     }
  482.     xfree(clientTable[client->index].resources);
  483.     clientTable[client->index].buckets = 0;
  484. }
  485.  
  486. FreeAllResources()
  487. {
  488.     int    i;
  489.  
  490.     for (i=0; i<currentMaxClients; i++) 
  491.     {
  492.         if (clientTable[i].buckets) 
  493.         FreeClientResources(clients[i]);
  494.     }
  495. }
  496.  
  497. Bool
  498. LegalNewID(id, client)
  499.     XID id;
  500.     register ClientPtr client;
  501. {
  502.     return ((client->clientAsMask == CLIENT_BITS(id)) && !(id & SERVER_BIT) &&
  503.         ((clientTable[client->index].expectID <= id) ||
  504.          !LookupIDByClass(id, RC_ANY)));
  505. }
  506.  
  507. /*
  508.  *  LookupIDByType returns the object with the given id and type, else NULL.
  509.  */ 
  510. pointer
  511. LookupIDByType(id, rtype)
  512.     XID id;
  513.     RESTYPE rtype;
  514. {
  515.     int    cid;
  516.     register    ResourcePtr res;
  517.  
  518.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  519.     {
  520.     res = clientTable[cid].resources[Hash(cid, id)];
  521.  
  522.     for (; res; res = res->next)
  523.         if ((res->id == id) && (res->type == rtype))
  524.         return res->value;
  525.     }
  526.     return (pointer)NULL;
  527. }
  528.  
  529. /*
  530.  *  LookupIDByClass returns the object with the given id and any one of the
  531.  *  given classes, else NULL.
  532.  */ 
  533. pointer
  534. LookupIDByClass(id, classes)
  535.     XID id;
  536.     RESTYPE classes;
  537. {
  538.     int    cid;
  539.     register    ResourcePtr res;
  540.  
  541.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  542.     {
  543.     res = clientTable[cid].resources[Hash(cid, id)];
  544.  
  545.     for (; res; res = res->next)
  546.         if ((res->id == id) && (res->type & classes))
  547.         return res->value;
  548.     }
  549.     return (pointer)NULL;
  550. }
  551. @
  552.